package com.example.server.netty;

import com.example.server.ServerImpl;
import com.example.transport.message.PublishReponse;
import com.example.transport.message.PublishRequest;
import com.example.transport.message.Request;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolver;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;

import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

public class DefaultNettyServer extends ServerImpl {

    Logger logger = Logger.getLogger(getClass().getName());

    private EventLoopGroup bossGroup;

    private EventLoopGroup workGroup;

    public DefaultNettyServer(int port) {
        super(port);
    }

    @Override
    public void init() throws Exception {

    }

    @Override
    public void start() throws Exception {
        this.bossGroup = new NioEventLoopGroup(1);
        this.workGroup = new NioEventLoopGroup(20);
        ServerBootstrap bootstrap = new ServerBootstrap().group(bossGroup, workGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer() {
            @Override
            protected void initChannel(Channel ch) throws Exception {
                ClassResolver classResolver = ClassResolvers.cacheDisabled(getClass().getClassLoader());
                ch.pipeline().addLast("decoder", new ObjectDecoder(classResolver));
                ch.pipeline().addLast("encoder", new ObjectEncoder());
                ch.pipeline().addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS) {
                    @Override
                    protected void channelIdle(ChannelHandlerContext ctx, IdleStateEvent evt) throws Exception {
                        if (evt.state() == IdleState.WRITER_IDLE) {
                            logger.warning("节点: " + ctx.channel().id() + " WRITER_IDLE WRITER_IDLE WRITER_IDLE ...");
                        }
                        if (evt.state() == IdleState.READER_IDLE) {
                            logger.warning("节点: " + ctx.channel().id() + " READER_IDLE READER_IDLE READER_IDLE ...");
                        }
                    }
                });
                ch.pipeline().addLast(new ChannelDuplexHandler() {
                    @Override
                    public void channelActive(ChannelHandlerContext ctx) throws Exception {
                        super.channelActive(ctx);
                    }

                    @Override
                    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
                        super.channelInactive(ctx);
                    }

                    @Override
                    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                        logger.warning("server服务消息:" + msg.toString());
                        if (msg instanceof PublishRequest) {
                            PublishReponse publishReponse = new PublishReponse();
                            publishReponse.setSuccess(true);
                            publishReponse.setRequest((Request) msg);
                            ctx.channel().writeAndFlush(publishReponse).sync();
                        }

                    }
                });
            }
        }).localAddress(getPort()).option(ChannelOption.SO_BACKLOG, 1024).childOption(ChannelOption.SO_KEEPALIVE, true);
        ChannelFuture channelFuture = bootstrap.bind(getPort()).sync();
        if (channelFuture.isSuccess()) {
            logger.warning("netty server started at " + getPort());
        }
    }

    @Override
    public void stop() throws Exception {
        if (!bossGroup.isShutdown()) {
            bossGroup.shutdownGracefully();
        }
        if (!workGroup.isShutdown()) {
            workGroup.shutdownGracefully();
        }
    }
}
